﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.InteropServices;

namespace CardPlay.Model.Primitives
{
    [StructLayout(LayoutKind.Sequential)]
    public struct Rectangle
    {
        private int _x;
        private int _y;
        private int _width;
        private int _height;

        public static readonly Rectangle Empty;

        static Rectangle()
        {
            Empty = new Rectangle();
        }

        public Rectangle(int x, int y, int width, int height)
        {
            _x = x;
            _y = y;
            _width = width;
            _height = height;
        }

        public Rectangle(Point location, Size size)
        {
            _x = location.X;
            _y = location.Y;
            _width = size.Width;
            _height = size.Height;
        }

        public static Rectangle FromLTRB(int left, int top, int right, int bottom)
        {
            return new Rectangle(left, top, right - left, bottom - top);
        }


#if !WINDOWS_PHONE
        [Browsable(false)]
#endif
        public Point Location
        {
            get
            {
                return new Point(X, Y);
            }
            set
            {
                X = value.X;
                Y = value.Y;
            }
        }
        
#if !WINDOWS_PHONE
        [Browsable(false)]
#endif
        public Size Size
        {
            get { return new Size(Width, Height); }
            set 
            { 
                Width = value.Width; 
                Height = value.Height;
            }
        }

        public int X
        {
            get { return _x; }
            set { _x = value; }
        }

        public int Y
        {
            get { return _y; }
            set { _y = value; }
        }

        public int Width
        {
            get { return _width; }
            set
            {
                _width = value;
            }
        }

        public int Height
        {
            get { return _height; }
            set { _height = value; }
        }

#if !WINDOWS_PHONE
        [Browsable(false)]
#endif
        public int Left
        {
            get
            {
                return X;
            }
        }
        
#if !WINDOWS_PHONE
        [Browsable(false)]
#endif
        public int Top
        {
            get
            {
                return Y;
            }
        }
        
#if !WINDOWS_PHONE
        [Browsable(false)]
#endif
        public int Right
        {
            get
            {
                return (X + Width);
            }
        }
        
#if !WINDOWS_PHONE
        [Browsable(false)]
#endif
        public int Bottom
        {
            get
            {
                return (Y + Height);
            }
        }

#if !WINDOWS_PHONE
        [Browsable(false)]
#endif
        public bool IsEmpty
        {
            get
            {
                return (_height == 0) && (_width == 0) && (_x == 0) && (_y == 0);
            }
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Rectangle))
            {
                return false;
            }
            var rectangle = (Rectangle)obj;
            return (rectangle.X == X) && (rectangle.Y == Y) && (rectangle.Width == Width) && (rectangle.Height == Height);
        }

        public static bool operator ==(Rectangle left, Rectangle right)
        {
            return (left.X == right.X) && (left.Y == right.Y) && (left.Width == right.Width) && (left.Height == right.Height);
        }

        public static bool operator !=(Rectangle left, Rectangle right)
        {
            return !(left == right);
        }

        public bool Contains(int x, int y)
        {
            return ((((X <= x) && (x < (X + Width))) && (Y <= y)) && (y < (Y + Height)));
        }

        public bool Contains(Point pt)
        {
            return Contains(pt.X, pt.Y);
        }

        public bool Contains(Rectangle rect)
        {
            return ((((X <= rect.X) && ((rect.X + rect.Width) <= (X + Width))) && (Y <= rect.Y)) && ((rect.Y + rect.Height) <= (Y + Height)));
        }

        public override int GetHashCode()
        {
            return (((X ^ ((Y << 13) | (Y >> 0x13))) ^ ((Width << 0x1a) | (Width >> 6))) ^ ((Height << 7) | (Height >> 0x19)));
        }

        public void Inflate(int width, int height)
        {
            X -= width;
            Y -= height;
            Width += 2 * width;
            Height += 2 * height;
        }

        public void Inflate(Size size)
        {
            Inflate(size.Width, size.Height);
        }

        public static Rectangle Inflate(Rectangle rect, int x, int y)
        {
            var rectangle = rect;
            rectangle.Inflate(x, y);
            return rectangle;
        }

        public void Intersect(Rectangle rect)
        {
            var rectangle = Intersect(rect, this);
            X = rectangle.X;
            Y = rectangle.Y;
            Width = rectangle.Width;
            Height = rectangle.Height;
        }

        public static Rectangle Intersect(Rectangle a, Rectangle b)
        {
            var x = Math.Max(a.X, b.X);
            var num2 = Math.Min(a.X + a.Width, b.X + b.Width);
            var y = Math.Max(a.Y, b.Y);
            var num4 = Math.Min(a.Y + a.Height, b.Y + b.Height);
            if ((num2 >= x) && (num4 >= y))
            {
                return new Rectangle(x, y, num2 - x, num4 - y);
            }
            return Empty;
        }

        public bool IntersectsWith(Rectangle rect)
        {
            return ((((rect.X < (X + Width)) && (X < (rect.X + rect.Width))) && (rect.Y < (Y + Height))) && (Y < (rect.Y + rect.Height)));
        }

        public static Rectangle Union(Rectangle a, Rectangle b)
        {
            var x = Math.Min(a.X, b.X);
            var num2 = Math.Max(a.X + a.Width, b.X + b.Width);
            var y = Math.Min(a.Y, b.Y);
            var num4 = Math.Max(a.Y + a.Height, b.Y + b.Height);
            return new Rectangle(x, y, num2 - x, num4 - y);
        }

        public void Offset(Point pos)
        {
            Offset(pos.X, pos.Y);
        }

        public void Offset(int x, int y)
        {
            X += x;
            Y += y;
        }

        public override string ToString()
        {
            return ("{X=" + X.ToString(CultureInfo.CurrentCulture) + ",Y=" + Y.ToString(CultureInfo.CurrentCulture) + ",Width=" + Width.ToString(CultureInfo.CurrentCulture) + ",Height=" + Height.ToString(CultureInfo.CurrentCulture) + "}");
        }
    }
}
